package com.szholly.plug.safe.entity.workday;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

import com.szholly.data.general.RowBase;

/**
 * 计算工作时间
 * 
 * @author WY
 */
public class WorkDayUtils {

	static Logger logger = Logger.getLogger(WorkDayUtils.class);
	// 秒
	public static long SECOND = 1000;
	// 分钟
	public static long MINUTE = SECOND * 60;
	// 小时
	public static long HOUR = MINUTE * 60;
	// 天
	public static long DAY = HOUR * 24;

	/**
	 * 默认的日期格式:yyyy-MM-dd HH:mm:ss
	 */
	public static final String DEFAULTFORMAT = "yyyy-MM-dd HH:mm:ss";
	/**
	 * 默认的日期格式:yyyy-MM-dd HH:mm
	 */
	public static final String MINUTE_FORMAT = "yyyy-MM-dd HH:mm";

	/**
	 * 默认的日期格式:yyyy-MM-dd HH
	 */
	public static final String CLOCK_FORMAT = "yyyy-MM-dd HH";
	/**
	 * 默认的日期格式:yyyy-MM-dd
	 */
	public static final String SIMPLE_FORMAT = "yyyy-MM-dd";
	/**
	 * 计算起始日期与结束日期之间的有效工作时间
	 * <p>
	 * <ul>
	 * <li>不包含法定节假日
	 * <li>
	 * <li>不包含非工作时间</li>
	 * <li>不包含周六、周末及调休时间</li>
	 * </ul>
	 * </p>
	 * 
	 * @param startTime
	 *            起始日期
	 * @param endTime
	 *            结束日期
	 * @param holidays
	 *            节假日时间集合
	 * @param amStart
	 *            上午上班时间
	 * @param amEnd
	 *            上午下班时间
	 * @param pmStart
	 *            下午上班时间
	 * @param pmEnd
	 *            下午下班时间
	 * @return 分钟数
	 */
	public static long getMinutes(Date startTime, Date endTime,
			Map<String, RowBase> holidays, String amStart, String amEnd,
			String pmStart, String pmEnd) {
		SimpleDateFormat ft = new SimpleDateFormat(MINUTE_FORMAT);
		String startDateStr = ft.format(startTime);
		String endDateStr = ft.format(endTime);
		return getMinutes(startDateStr, endDateStr, holidays, amStart, amEnd, pmStart, pmEnd);
	}
	/**
	 * 计算起始日期与结束日期之间的有效工作时间
	 * <p>
	 * <ul>
	 * <li>不包含法定节假日
	 * <li>
	 * <li>不包含非工作时间</li>
	 * <li>不包含周六、周末及调休时间</li>
	 * </ul>
	 * </p>
	 * 
	 * @param startTime
	 *            起始日期
	 * @param endTime
	 *            结束日期
	 * @param holidays
	 *            节假日时间集合
	 * @param amStart
	 *            上午上班时间
	 * @param amEnd
	 *            上午下班时间
	 * @param pmStart
	 *            下午上班时间
	 * @param pmEnd
	 *            下午下班时间
	 * @return 分钟数
	 */
	public static long getMinutes(String startTime, String endTime,
			Map<String, RowBase> holidays, String amStart, String amEnd,
			String pmStart, String pmEnd) {
		long totalMinutes = 0;
		Date amStartDate = null;// 上午上班时间
		Date amEndDate = null;// 上午下班时间
		Date pmStartDate = null;// 下午上班时间
		Date pmEndDate = null;// 下午下班时间
		SimpleDateFormat ft = new SimpleDateFormat(MINUTE_FORMAT);
		SimpleDateFormat cft = new SimpleDateFormat(CLOCK_FORMAT);
		try {
			Date realStartTime = ft.parse(startTime);
			Date realEndTime = ft.parse(endTime);
			if (realStartTime.getTime() > realEndTime.getTime()) {
				// 如果起始时间大于结束时间，时间互换
				realStartTime = ft.parse(endTime);
				realEndTime = ft.parse(startTime);
			}
			amStartDate = ft.parse(startTime.substring(0, 11) + amStart);
			amEndDate = ft.parse(startTime.substring(0, 11) + amEnd);
			pmStartDate = ft.parse(startTime.substring(0, 11) + pmStart);
			pmEndDate = ft.parse(startTime.substring(0, 11) + pmEnd);

			if (realStartTime.getTime() < amStartDate.getTime()) {
				// 如果小于当天8点，将其置为当天8天(因为你是8点上班)
				realStartTime.setTime(amStartDate.getTime());
			} else if (realStartTime.getTime() > amEndDate.getTime()
					&& realStartTime.getTime() < pmStartDate.getTime()) {
				// 如果大于当天12点，且小于当天14点，将其置为当天14点(因为你下午是14点上班)
				realStartTime.setTime(pmStartDate.getTime());
			} else if (realStartTime.getTime() > pmEndDate.getTime()) {
				// 如果大于当天18点，将其置为第二天8天
				realStartTime.setTime(amStartDate.getTime() + DAY);
			}
			amStartDate = ft.parse(endTime.substring(0, 11) + amStart);
			amEndDate = ft.parse(endTime.substring(0, 11) + amEnd);
			pmStartDate = ft.parse(endTime.substring(0, 11) + pmStart);
			pmEndDate = ft.parse(endTime.substring(0, 11) + pmEnd);

			if (realEndTime.getTime() < amStartDate.getTime()) {
				// 如果小于当天8点，将其置为昨天18点
				String yestodayTime = getAddDay(endTime, -1);
				realEndTime.setTime(ft.parse(
						yestodayTime.substring(0, 10) + pmEnd).getTime());
			} else if (realEndTime.getTime() > amEndDate.getTime()
					&& realEndTime.getTime() < pmStartDate.getTime()) {
				// 如果大于当天12点，且小于当天14点，将其置为当天12点(因为你上午是12点下班)
				realEndTime.setTime(amEndDate.getTime());
			} else if (realEndTime.getTime() > pmEndDate.getTime()) {
				// 如果大于当天18点，将其置为当天18天(因为你是18点下班)
				realEndTime.setTime(pmEndDate.getTime());
			}

			String _startClock = ft.format(realStartTime.getTime()).substring(
					0, 13);
			Date _startClockDate = cft.parse(_startClock);
			long startMinutes = realStartTime.getTime();
			long endMinutes = 0;
			for (long idxTime = _startClockDate.getTime(); idxTime < realEndTime
					.getTime(); idxTime += HOUR) {
				Date idxDate = new Date(idxTime);
				endMinutes = idxTime;
				if (endMinutes < startMinutes) {
					continue;
				}
				String currentTime = ft.format(idxDate).substring(0, 11);
				long idxTimes = idxDate.getTime();
				long amStartTimes = ft.parse(currentTime + amStart).getTime();
				long amEndTimes = ft.parse(currentTime + amEnd).getTime();
				long pmStartTimes = ft.parse(currentTime + pmStart).getTime();
				long pmEndTimes = ft.parse(currentTime + pmEnd).getTime();
				if (holidays.containsKey(currentTime)) {
					totalMinutes += 0;
				} else if (((idxTimes - 1) >= amStartTimes && idxTimes <= amEndTimes)
						|| ((idxTimes - 1) >= pmStartTimes && idxTimes <= pmEndTimes)) {
					logger.debug(getOOclick(endMinutes));
					totalMinutes += (endMinutes - startMinutes) / MINUTE;
				}
				startMinutes = idxDate.getTime();
			}
			//
			totalMinutes += getMinutes(realEndTime);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return totalMinutes;
	}

	/**
	 * 将分钟数转换为"xx天xx小时xx分钟"
	 * 一天按24小时计算
	 * 
	 * @param totalMinutes
	 *            [long]
	 * @return [String] "xx天xx小时xx分钟"
	 */
	public static String minutesToDays(long totalMinutes) {
		StringBuffer sBuf = new StringBuffer();
		double _day = totalMinutes * 1.0 / (60 * 24);
		if (_day > 1) {
			sBuf.append((int) _day).append("天");
			long _syMinutes = totalMinutes - (60 * 24 * (int) _day);
			sBuf.append(minutesToHours(_syMinutes));
		} else {
			sBuf.append(minutesToHours(totalMinutes));
		}
		return sBuf.toString();
	}
	
	/**
	 * 将分钟数转换为"xx小时xx分钟"
	 * 
	 * @param [long] totalMinutes 分钟数
	 * @return
	 */
	public static String formatDate(Date _date, String fmt) {
		SimpleDateFormat ft = new SimpleDateFormat(fmt);
		return ft.format(_date);
	}

	/**
	 * 将分钟数转换为"xx小时xx分钟"
	 * 
	 * @param [long] totalMinutes 分钟数
	 * @return
	 */
	public static String minutesToHours(long totalMinutes) {
		StringBuffer sBuf = new StringBuffer();
		if (totalMinutes < 60) {
			sBuf.append(totalMinutes).append("分钟");
		} else {
			long hour = totalMinutes / 60;
			long minutes = totalMinutes - (hour * 60);
			sBuf.append(hour).append("小时");
			if(minutes>0){
				sBuf.append(minutes).append("分钟");
			}
		}
		return sBuf.toString();
	}

	/**
	 * 计算两个时间之间的工作天数
	 * 
	 * @param time1
	 *            [String] 开始日期
	 * @param time2
	 *            [String] 结束日期
	 * @return 天数
	 */
	public static double getDD(String time1, String time2) {
		double quot = 0d;
		SimpleDateFormat ft = new SimpleDateFormat(DEFAULTFORMAT);
		try {
			Date date1 = ft.parse(time1);
			Date date2 = ft.parse(time2);
			quot = date2.getTime() - date1.getTime();
			quot = quot * 1.0 / DAY;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return quot;
	}

	/**
	 * 获取进行日期增量(加减运算)后的日期字符串
	 * 
	 * @param date
	 *            日期字符串
	 * @param day
	 *            增量值,可取正/负值
	 * @return 日期字符串
	 */
	public static String getAddDay(String date, int day) {
		SimpleDateFormat from = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 这里的格式可以自己设置
		Calendar startDT = Calendar.getInstance();
		startDT.setTime(getDate(date));
		startDT.add(Calendar.DAY_OF_MONTH, day);
		return from.format(startDT.getTime());
	}

	/**
	 * 获取进行日期增量(加减运算)后的日期对象
	 * 
	 * @param date
	 *            日期对象
	 * @param day
	 *            增量值,可取正/负值
	 * @return 日期对象
	 */
	public static Date getAddDay(Date date, int day) {
		Calendar startDT = Calendar.getInstance();
		startDT.setTime(date);
		startDT.add(Calendar.DAY_OF_MONTH, day);
		return startDT.getTime();
	}

	/**
	 * 获取日期的分钟数，如"2014-01-20 08:55:01",返回 55
	 * 
	 * @param date
	 *            日期对象
	 * @return
	 */
	public static int getMinutes(Date date) {
		Calendar startDT = Calendar.getInstance();
		startDT.setTime(date);
		return startDT.get(Calendar.MINUTE);
	}

	/**
	 * 将分钟数转换为整点时间字符，如"2015-04-07 16"
	 * 
	 * @param minutes
	 *            分钟数
	 * @return 字符日期格式
	 */
	public static String getOOclick(long minutes) {
		SimpleDateFormat from = new SimpleDateFormat(CLOCK_FORMAT);
		return from.format(new Date(minutes));
	}

	/**
	 * 将字符串的日期转换为日期对象
	 * 
	 * @param date
	 *            字符串格式的日期，如："2015-01-03 08:33:00"
	 * @return 返回java.util.Date类型的日期对象
	 */
	public static Date getDate(String date) {
		SimpleDateFormat from = new SimpleDateFormat(DEFAULTFORMAT);
		long t;
		try {
			t = from.parse(date).getTime();
			Date d = new Date(t);
			return d;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}
	/**
	 * 将字符串的日期转换为日期对象
	 * 
	 * @param date
	 *            字符串格式的日期，如："2015-01-03 08:33:00"
	 * @return 返回java.util.Date类型的日期对象
	 */
	public static int getMonth(Date data) {
		Calendar startDT = Calendar.getInstance();
		startDT.setTime(data);
		return startDT.get(Calendar.MONTH);
	}
	public static void main(String[] args) throws ParseException {
		Map<String, RowBase> holidays = new HashMap<String, RowBase>();
		String BeginDateStr = "2015-04-01 13:01:10";
		String EndDateStr = "2015-04-07 18:02:05";
		String amStart = " 08:00";
		String amEnd = " 12:00";
		String pmStart = " 13:00";
		String pmEnd = " 17:00";
		long totalMinutes = getMinutes(BeginDateStr, EndDateStr, holidays,
				amStart, amEnd, pmStart, pmEnd);
		System.out.println("开始时间： " + BeginDateStr);
		System.out.println("结束时间： " + EndDateStr);
		System.out.println(minutesToDays(totalMinutes));
	}

}
